package com.ptc.ims.client.presenter;

import java.util.List;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HasWidgets;
import com.ptc.ims.client.InventoryServiceAsync;
import com.ptc.ims.client.event.CreateProductEvent;
import com.ptc.ims.client.event.EditProductEvent;
import com.ptc.ims.client.util.Validator;
import com.ptc.ims.shared.Product;

public class ProductListPresenter 
extends AbstractPresenter 
implements Presenter 
{
	public static final String PAGE = "list";
	public final Display view;
	
	public ProductListPresenter(InventoryServiceAsync inventoryService, HandlerManager eventBus, Display view) 
	{
		super(inventoryService, eventBus);
		this.view = view;
	}
	
	/** Overriden Methods */

	@Override
	public void go(HasWidgets container)
	{		
		super.go(container);
		fetchProducts();
	}	
	
	public void bind()
	{
		view.getAddButton().addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event)
			{
				Validator validator = new Validator();
				List<String> errors = validator.validate(view.getProductName().getValue(), view.getPrice().getValue());
				if (errors.isEmpty())
				{
					addProduct();
				}
				else
				{
					String errorMessage = "<ul>";
					for (String error : errors)
					{
						errorMessage += "<li>" + error + "</li>";
					}
					errorMessage += "</ul>";
					createSimpleDialog("OK", "Validation Error", errorMessage).show();
				}				
			}
		});
		view.getDeleteButton().addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event)
			{
				deleteSeletedProducts();				
			}
		});
		view.getList().addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event)
			{
				view.showMoreOptionsButton(event);			
			}
		});		
		
		view.getCreateButton().addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event) 
			{
				getHandlerManager().fireEvent(new CreateProductEvent());
			}
		});
		view.getEditButton().addClickHandler(new ClickHandler() {			
			@Override
			public void onClick(ClickEvent event)
			{
				List<String> selectedRows = view.getSelectedRows();
				if (selectedRows.size() == 1)
				{
					getHandlerManager().fireEvent(new EditProductEvent(selectedRows.get(0)));		
				}						
			}
		});
	}
	
	@Override
	public DisplayView getView()
	{		
		return view;
	}
	
	/**
	 * fetch products remotely
	 */
	public void fetchProducts()
	{
		AsyncCallback<List<Product>> fetchProductsCallBack = new AsyncCallback<List<Product>>() 
		{
			@Override
			public void onFailure(Throwable caught) 
			{
				createSimpleDialog("OK", "Server Error", "An error occured while retrieving records").show();
			}

			@Override
			public void onSuccess(List<Product> result) 
			{
				view.setData(result);
			}		
		};		
		getInventoryService().fetchProducts(fetchProductsCallBack);
	}	

	public void addProduct()
	{
		String productName = view.getProductName().getValue();
		String price = view.getPrice().getValue();
		final Product product = new Product(null, productName, Double.valueOf(price));
		
		AsyncCallback<String> addProductCallBack = new AsyncCallback<String>()
		{
			@Override
			public void onFailure(Throwable caught)
			{
				createSimpleDialog("OK", "Server Error", "An error occured while adding records").show();
			}

			@Override
			public void onSuccess(String productId)
			{
				product.setId(productId);
				view.addNewRow(product);
				createSimpleDialog("OK", "Add Successful", "Successfully added new record with ID " + productId).show();			
			}
			
		};
		getInventoryService().addProduct(product, addProductCallBack);
	}
	
	/**
	 * removes one or more product
	 */
	public void deleteSeletedProducts()
	{
		final List<String> selectedRows = view.getSelectedRows();
		if (!selectedRows.isEmpty())
		{
			AsyncCallback<List<String>> deleteProductCallBack = new AsyncCallback<List<String>>() 
			{
				@Override
				public void onFailure(Throwable caught)
				{
					createSimpleDialog("OK", "Delete Error", "An error occured while deleting records").show();
				}

				@Override
				public void onSuccess(List<String> deletedRows)
				{
					view.removeSelectedRows(deletedRows);
					view.showMoreOptionsButton(null);
					createSimpleDialog("OK", "Delete Successful", "Successfully deleted " + deletedRows.size() + " records").show();					
				}
			};
			getInventoryService().removeProduct(selectedRows, deleteProductCallBack);
		}
	}	
	
	public interface Display extends DisplayView
	{
		/** View Elements */
		
		/**
		 * when clicked will add a new row, with blank fields
		 * @return
		 */
		HasClickHandlers getAddButton();
		
		/**
		 * when clicked it will redirect the user to the create a product page
		 * @return
		 */
		HasClickHandlers getCreateButton();
		
		/**
		 * when clicked it will redirect the user to the update page
		 * @return
		 */
		HasClickHandlers getEditButton();
		
		/**
		 * will delete currently selected fields
		 * @return
		 */
		HasClickHandlers getDeleteButton();	
		
		/**
		 * the product name to add
		 * @return
		 */
		HasValue<String> getProductName();
		
		/**
		 * the price of the product to add
		 * @return
		 */
		HasValue<String> getPrice();
		
		/** Utilities */
		
		/**
		 * 
		 * @return the container of the product list.
		 */
		HasClickHandlers getList();		
		
		/**
		 * will set the initial product list
		 * @param data
		 */
		void setData(List<Product> data);
		
		/**
		 * double-clicked cells are for used for editing
		 * @param event
		 * @return the coordinate of the cell where the double click event was triggered
		 * index 0 - row, 1 - column
		 */
		int[] getDoubleClickedCell(ClickEvent event);
		
		/**
		 * 
		 * @return empty list when no rows is selected
		 */
		List<String> getSelectedRows();
		
		/**
		 * 
		 * @param productIds
		 */
		
		void removeSelectedRows(List<String> productIds);
		/**
		 * add new entry on the display
		 * @param product
		 */
		void addNewRow(Product product);
		
		/**
		 * toggles the edit and delete button
		 */
		void showMoreOptionsButton(ClickEvent event);
		
	}
}
